namespace taurus.client {
    /**
     * SocketCode
     */
    export enum SocketCode {
        /**
         * 连接成功
         */
        Connect,
        Disconnect,
        /**
         * 未知异常
         */
        Exception,
        /**
         * 连接服务异常
         */
        ExceptionOnConnect,
        /**
         * 发送数据流错误
         */
        SendError,
        /**
         * 接收服务器数据流异常
         */
        ExceptionOnReceive,
        /**
         * 服务器连接超时
         */
        TimeoutDisconnect,
        /**
         * 服务器断开连接
         */
        DisconnectByServer
    }

    /**
     * ConnectionProtocol
     */
    export enum ConnectionProtocol {
        WebSocket, Web,
    }

    /**
     * Client Event
     */
    export class NetClientEvent {
        public static readonly Connect: string = "connect";

        public static readonly OnEvent: string = "onevent";
    }

    /**
     * TaurusClient
     */
    export class TaurusClient {
        private _id: number;
        private _connect: boolean;
        private _gameId: string;
        private _currentIp: string;

        private _scoket: IScoketLayer;

        private _dispatcher: EventDispatcher;
        private _responseMap: any;
        _isKill: boolean = false;
        _protocolCompression:number=100;
        private static _tempID: number = 0;

        private static _getValidID(): number {
            return ++TaurusClient._tempID;
        }

        /**
         * 
         * @param host
         * @param game
         * @param protocol
         * @param secure
         */
        public constructor(host: string, game: string, protocol: ConnectionProtocol = ConnectionProtocol.WebSocket, secure: boolean = false) {
            switch (protocol) {
                case ConnectionProtocol.WebSocket:
                    this._scoket = new SocketEngine(this,secure);
                    break;
                case ConnectionProtocol.Web:
                    this._scoket = new HttpClient(host);
                    this._connect = true;
                    break;
            }
            this.__initialize(host, game);

        }

        private __initialize(host: string, game: string) {
            this._currentIp = host;
            this._gameId = game;
            this._id = TaurusClient._getValidID();
            this._dispatcher = new EventDispatcher();
            this._responseMap = {};
            NetManager.addNetClient(this);

            this._scoket.setOnConnect(function (code: SocketCode) {
                if (code == SocketCode.Connect)
                    this._connect = true;
                else
                    this._connect = false;
                var evt = new Event(NetClientEvent.Connect);
                evt.setParameter("code", code);
                this._dispatcher.dispatchEvent(evt);

            }, this);

            this._scoket.setOnEvent(function (msg: Message) {
                if (this._connect) {
                    var evt = new Event(NetClientEvent.OnEvent);
                    evt.setParameter("msg", msg);
                    this._dispatcher.dispatchEvent(evt);
                    if (NetManager.debug_print) {
                        var str = this.getProtocol() == ConnectionProtocol.Web ? "WEB" : "WEBSOCKET";
                        var data_str = msg.useText ? msg.textParam : (msg.param != null ? msg.param.toJson() : "null");
                        log.debug("Event [" + str + "->" + msg.command + "] data:" + data_str);
                    }
                }
            }, this);
        }

        /**
         * 添加事件
         * @param eventType
         * @param listener
         */
        public addEventListener(eventType: string, listener: Function, thisObject: any) {
            this._dispatcher.addEventListener(eventType, listener, thisObject);
        }

        /**
         * 移除所有事件
         */
        public removeAllListener() {
            this._dispatcher.removeAllListener();
        }

        /**
         * 移除指定事件
         * @param eventType
         * @param listener
         */
        public removeEventListener(eventType: string, listener: Function, thisObject: any) {
            this._dispatcher.removeEventListener(eventType, listener, thisObject);
        }

        /**
         * 连接服务器
         */
        public connect() {
            this._scoket.connect(this._currentIp, this._gameId);
        }

        /**
         * Kill net connection.
         */
        public killConnection() {
            this.removeAllListener();
            this._responseMap = {};
            this._scoket.disconnect();
            this._connect = false;
            this._isKill = true;
        }

        /// <summary>
        /// 发送网络消息包
        /// </summary>
        /// <param name="msg">消息数据对象</param>
        protected _send(msg: Message) {
            if (msg == null)
                return;
            if (NetManager.debug_print) {
                var str = this.getProtocol() == ConnectionProtocol.Web ? "WEB" : "WEBSOCKET";
                var data_str = msg.useText ? msg.textParam : (msg.param != null ? msg.param.toJson() : "null");
                str = "Requst [" + str + "->" + msg.command + "] ->param:" + data_str;
                log.debug(str);
            }
            if (msg.callback != null) {
                this._responseMap[<any>msg] = msg.callback;
                var self = this;
                msg.callback = function (res: MessageResponse) {
                    var callback = self._responseMap[<any>res.messageData];
                    delete self._responseMap[<any>res.messageData];
                    if (NetManager.debug_print) {
                        var str = self.getProtocol() == ConnectionProtocol.Web ? "WEB" : "WEBSOCKET";
                        var data_str = msg.useText ? msg.textParam : (msg.param != null ? msg.param.toJson() : "null");
                        str = "Response [" + str + "->" + msg.command + "] ->result:" + res.returnCode + " param:" + data_str;
                        log.debug(str);
                    }
                    callback.call(res.messageData.thisObject, res);
                };
            }
            this.sendData(msg);
        }


        /**
         * 发送网络消息包
         * @param cmd 		网络协议指令Key
         * @param param		参数
         * @param callback	网络消息回调
         * @param thisObject 回调对象
         * @return
         */
        public send(cmd: string, param: ITObject, callback: (res: MessageResponse) => void, thisObject: any): Message {
            var msg = new Message();
            msg.command = cmd;
            msg.param = param;
            msg.thisObject = thisObject;
            msg.callback = callback;
            msg.useText = false;
            this._send(msg);
            return msg;
        }

        /**
         * 发送网络消息包
         * @param cmd 		网络协议指令Key
         * @param text		JSON 文本
         * @param callback	网络消息回调
         * @param thisObject 回调对象
         * @return
         */
        public  sendText(cmd:string, text:string, callback: (res: MessageResponse) => void, thisObject: any) : Message {
            var msg = new Message();
            msg.useText = true;
            msg.command = cmd;
            msg.textParam = text;
            msg.thisObject = thisObject;
            msg.callback = callback;
            msg.useText = true;
            this._send(msg);
            return msg;
        }

        /**
         * 发送数据线程方法
         * @param message
         */
        private sendData(msg: Message) {
            this._scoket.write(msg);
        }

        /**
         * 清理响应回调
         */
        public clearResponse() {
            this._responseMap = {};
        }

        /**
         * The net client id
         * @return
         */
        public getId(): number {
            return this._id;

        }

        /**
         * The curren ip
         * @return
         */
        public getCurrentIp(): string {
            return this._currentIp;
        }

        /**
         * The curren Game ID
         * @return
         */
        public getGameID(): string {
            return this._gameId;
        }

        /**
         * 网络是否已连接
         * @return
         */
        public isConnected(): boolean {
            return this._connect;
        }

        /**
         * 当前网络类型
         * @return
         */
        public getProtocol(): ConnectionProtocol {
            return this._scoket.getProtocol();
        }

        /**
         * 网络延时
         * @return
         */
        public getAveragePingTime(): number {
            return this._scoket.getAveragePingTime();
        }

        /**
         * 获取服务器Session字符
         * @return
         */
        public getSession(): string {
            return this._scoket.getSession();
        }

        /**
         * 设置服务器Session字符
         * @param session
         */
        public setSession(session: string) {
            this._scoket.setSession(session);
        }

        /**
         * 设置压缩阀值
         * @param protocolCompression
         */
        public setProtocolCompression(protocolCompression:number) {
            this._protocolCompression = protocolCompression;
        }

        /**
         * 获取压缩阀值
         * 
         */
        public getProtocolCompression():number {
            return this._protocolCompression;
        }

    }


}